/*
 * Created on 2005-7-16
 *
 */
package bma.common.thrift.bean;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.apache.thrift.TBase;
import org.apache.thrift.TFieldIdEnum;
import org.apache.thrift.meta_data.FieldMetaData;

import bma.common.langutil.bean.BeanClass;
import bma.common.langutil.bean.BeanClassBuilder;
import bma.common.langutil.bean.BeanObjectProperty;
import bma.common.langutil.bean.impl.BeanObjectSimple;
import bma.common.langutil.core.ClassUtil;
import bma.common.langutil.core.MType;
import bma.common.langutil.core.StringUtil;

public class BeanClassBuilderTBase implements BeanClassBuilder {

	final org.slf4j.Logger log = org.slf4j.LoggerFactory
			.getLogger(BeanClassBuilderTBase.class);

	public BeanClassBuilderTBase() {
		super();
	}

	@Override
	public BeanClass createClass(Class cls) {
		try {
			return doCreateClass(cls);
		} catch (Exception e) {
			log.warn("createClass fail", e);
			return null;
		}
	}

	protected BeanClass doCreateClass(Class cls) throws Exception {

		if (!ClassUtil.isExtendFrom(cls, TBase.class)) {
			return null;
		}

		Map<? extends TFieldIdEnum, FieldMetaData> fs = FieldMetaData
				.getStructMetaDataMap(cls);
		if (fs == null) {
			if (log.isDebugEnabled()) {
				log.debug("{} no FieldMetaData", cls.getName());
			}
			return null;
		}

		BeanObjectSimple bean = new BeanObjectSimple(cls);
		Map<String, BeanObjectPropertyTBase> propMap = new HashMap<String, BeanObjectPropertyTBase>();

		for (FieldMetaData fmdata : fs.values()) {
			String name = fmdata.fieldName;
			String cname = StringUtil.cap(name);

			Method gm;
			gm = ClassUtil.lookupMethod(cls, "get" + cname, null, null);
			if (gm == null) {
				gm = ClassUtil.lookupMethod(cls, "is" + cname, null, null);
			}
			if (gm == null) {
				if (log.isDebugEnabled()) {
					log.debug("{}.{} no get method", cls.getName(), name);
				}
				continue;
			}

			Method sm = ClassUtil.lookupMethod(cls, "set" + cname, null, null);
			if (sm == null) {
				if (log.isDebugEnabled()) {
					log.debug("{}.{} no set method", cls.getName(), name);
				}
				continue;
			}

			Method ism = ClassUtil.lookupMethod(cls, "isSet" + cname, null,
					null);

			Type rt = gm.getGenericReturnType();
			MType propType = new MType(rt);

			String propName = name;
			BeanObjectPropertyTBase prop = new BeanObjectPropertyTBase();
			prop.setName(propName);
			prop.setType(propType);
			prop.setGetMethod(gm);
			prop.setSetMethod(sm);
			prop.setIsSetMethod(ism);
			prop.setPrototype(gm);
			if (log.isDebugEnabled()) {
				log.debug("{} add property => {}:{}",
						new Object[] { cls.getName(), propName, propType });
			}
			propMap.put(propName, prop);
		}
		bean.setProperties(new ArrayList<BeanObjectProperty>(propMap.values()));
		return bean;

	}
}
